package com.yukefms.rule.interfaces;

import com.yukefms.engine.running.MatchedStatus;
import com.yukefms.engine.running.RunningContext;
import com.yukefms.rule.formula.interfaces.DynamicBAFormula;
import com.yukefms.rule.state.BARuleState;
import com.yukefms.jointpoint.BodyPointCloud;
import com.yukefms.rule.formula.interfaces.StaticBAFormula;

import java.util.List;

/**
 * @Description
 * A {@link BARule} is to specify body moving action, which is composed by trigger, invariant, stages, and scores, wherein,
 * the trigger is for action starting, the invariant is to specifying some body position/parts staying static during moving,
 * the stage has two parts, dynamic and response part, and the response part defines some desired action needs to
 * finish through dynamic action. The Semantics for {@link BARule} is as follows:
 *
 *  When the Trigger was satisfied, then the Rule was activated, and each Response part in Stage needs to finish by doing
 *  related Dynamic action. Meanwhile, the Invariant should be satisfied during all stages. Once one stage was finished,
 *  the performer could get Scores.
 *
 * [SYNTAX]
 * The BARule could be defined formally as follow:
 *
 *            [BARULE]  ::= [Trigger_Resp_Rule]
 *                      |  [BARule] [Timer] [Trial_Out]
 * [Trigger_Resp_Rule]  ::=  [Trigger] [Stage] [Invariant] [SCORE]
 *               [Stage] ::= [Dynamic][Response]
 *            [Trigger] ::= [StaticFromula]   [SCORE]
 *            [Dynamic] ::= [DynamicFormula]
 *           [Response] ::= [StaticFormula]  [SCORE]
 *          [Invariant] ::= [StaticFormula] [Tolerant_EPSILON] [SCORE]
 *
 *     // The following formula are the basics for building more complicate and procedural actions.
 *     [StaticFormula] ::=  [InLine(p1,p2)]
 *                      |   [InParallel(p1, p2, p3, p4)]
 *                      |   [horizonalAbove(p1, p2)]
 *                      |   [lineParallelPlane(p1, p2,p3,p4)]
 *                      |   [sameDistance(p1, p2, p3, p4)]
 *                      |  ...
 *     [DynamicFormula]  ::=  SitDown(p1)
 *                        |  keepStatic(p1)
 *                        |  ...
 *------------------------------------------------------------------------
 * [Semantics]
 * The semantics for BARule, especially for trigger_resp_rule, was defined as follow:
 * <ul>
 *     <li>in normal case (i.e., Matched and Success):
 *      When the TRIGGER was matched, then the rule was activiated (the player will get the starting score). The DYNAMIC action needs to continue performing
 *      until RESPONSE formula was arrived. Meanwhile, during the period, the INVARIANT formula must be satisfied all the time under certain tolerant Epsilon.
 *     </li>
 *     <li>no activated case (INACTIVATED) :
 *     When the TRIGGER was not matched, then the rule was still in INACTIVATED, then skip current point cloud for the next point cloud.
 *     </li>
 *     <li>Performing and keep Invariant (ACTIVATED/RIGHT_PERFORMING)</li>
 *     <li>Performing but failed Invariant (WRONG_PERFORMING)</li>
 *     <li>Activated but no Performing (NO_PERFORMING)</li>
 * </ul>
 *
 * [Transition Relation]
 *
 * INACTIVATED    -- triggered                 -->   ACTIVATED (SCORE(trigged))
 * INACTIVATED    -- NOT triggered             -->   INACTIVATED
 * INACTIVATED    -- time_out                  -->   FAILED
 *
 * ACTIVATED      -- time_out                  -->   FAILED
 * ACTIVATED      -- Dynamic & Invariant       -->  ACTIVATED (PERFORM_WELL)
 * ACTIVATED      -- Dynamic & NOT Invariant   -->  WRONG_PERFORM
 * ACTIVATED      -- NOT Dynamic               -->  UN_MATCHED (SCORE(triggered))
 * ACITVATED      -- Response                  -->  SUCCESS (SCORE(success))
 *
 * WRONG_PERFORM  -- Response                  -->  PARTIAL_MATCHED (SCORE(PARTIAL))
 * WRONG_PERFORM  -- NOT Dynamic               -->  UN_MATCHED (SCORE(triggered))
 * WRONG_PERFORM  -- Dynamic                   -->  WRONG_PERFORM
 * UN_MATCHED     --   trial_out               -->  FAILED
 * PARTIAL_MATCHED    -- trial_out             -->  FAILED


 * [RELATIONS of STATES]
 *
 * BARuleSTate
 *   if time out then FAILED
 *   if read_error then sending the infor to the front.
 *   -- INACTIVATED
 *        if triggered  then transition to ACTIVATED
 *   -- SUCCESS
 *        send the infor to the front
 *   -- FAILED
 *        send the infor to the front
 *   -- ACTIVATED
 *      if NOT Dynamic then transition to UNMATCHED
 *      else  if (NOT invarint)
 *          transition to WRONG_PERFORM
 *       else
 *          transition to PERFORM_WELL
 *
 *       -- PERFORM_WELL
 *       -- WRONG_PERFORM
 *   -- UNMATCHED
 *       -- PARTIAL_MATCHED
 *
 *
 *----------------------------------------------------------------------
 * [State Transition System]
 *   INACTIVATED   -- Trigger  --> ACTVIATED  <-- Dyanmic&Invariant  --> ACTIVATED   ======SCORE(Triggered)
 *      |                             |            \                           \
 *      TIME_OUT            NoT_Invariant        Not Dynamic           Response
 *      |                          \                        \                     \
 *      FAILED                 Wrong_PERFORMING               FAILED               SUCCESS  ==== SCORE (Triggered + Performing)
 *      ||                          ||                          ||
 *      ||                          ||                           ||
 *      SCORE = 0                SCORE (Triggered)              SCORE(TRIGGERED)
 *-----------------------------------------------------------
 *[STATES]
 * For each BARule, it might at one of following states:
 * <ul>
 *     <li>INACTIVATED: no triggered </li>
 *     <li>ACTIVATED: triggered and performing well </li>
 *     <li>WRONG_PERFORMING: activated and continue performing but failed in invarant</li>
 *     <li>UNMATCHED: rule is unmatched since possibly time out or no performing </li>
 *     <li>SUCCESS: rule is satisfied successfully based on rule semantics .</li>
 *     <li>FAILED: rule is failed since time out or the number of unmathced was out i.e., trial out</li>
 * </ul>
 * The principle semantics for BARule is defined as follows:
 * <ul>
 *     <li>
 *         [SKIP] when the rule was INACTIVATED, skip the input.
 *     </li>
 *     <li>
 *         [SUCCESS/FAILED]When rule was ACTIVATED, if performing Dynamic formula, the RESPONSE must be satisfied in certain time period
 *         during which the INVARIANT must ALWAYS be followed.
 *         If does not performing Dynamic formula, then the rule FAILED for the next round.
 *         If the invariant does not satified.
 *
 *         ACITIVATED STATE:
 *         if dynamic formula does not satisfied, then unmatched
 *         else if the invariant does not satisfied, then
 *                 transition to WRONG_PERFORMING.
 *         else if the response formula is satisfied, then
 *                transition to SUCCESS
 *         --------------------------
 *         WRONG_PERFORMING:
 *         if dynmaic formula does not satisfed, then UNMATCHED,
 *         if timout, then UNMATCHED.
 *          -----------------------------
 *          UN_Matched
 *          update TRIAL_OUT,TIMEER.
 *     </li>
 *     <li>
 *         [TRIAL-OUT]when failed over cerain times, then the rule was FAILED since trial out of times.
 *     </li>
 *     <li>
 *         [INPUT-ERROR] when the reader could not feed by proper jointCloud for certain times, then reset the rule state and
 *         the engine make reaction on such input error, for instance, by returning such infors to client.
 *     </li>
 * </ul>
 * @Author Ping
 * @Date 2021/6/18 22:53
 **/
public interface BARule {
    /**
     * rule name
     * @return
     */
    public String ruleName() ;

    public List<String> getInvolvedJointTypes() ;
    /**
     * the trigger formula for the rule
     * @return
     */
    public StaticBAFormula getTrigger() ;

    public String getTriggerName() ;

    /**
     * the response formula for the rule.
     * @return
     */
    public StaticBAFormula getResponse() ;
    public String getResponseName() ;
    public StaticBAFormula getInvariant() ;
    public String getInvariantName() ;
    public DynamicBAFormula getDynamic() ;
    public String getDynamicName() ;

    /**
     * reaction on the pointCloud
     * @param pointCloud
     * @param context
     */
    public void doReaction(BodyPointCloud pointCloud, RunningContext context) ;

    public void setRuleState(BARuleState state) ;
    public BARuleState getRuleState() ;

    /**
     * check if the rule could be activated for current read {@code pointCloud} under {@code context}.
     * @param pointCloud
     * @param context
     * @return
     */
    public default boolean isActivated(BodyPointCloud pointCloud, RunningContext context) {
        return this.getTrigger().matched(pointCloud, context) == MatchedStatus.TRUE ;
    }

    /**
     * check if the response of rule was already arrived for current read {@code pointCloud} under {@code context}.
     * @param pointCloud
     * @param context
     * @return
     */
    public default boolean responseArrived(BodyPointCloud pointCloud, RunningContext context) {
        if (this.getResponse() == null) {
            return true ;
        }
        return this.getResponse().matched(pointCloud, context) == MatchedStatus.TRUE ;
    }

    /**
     * check if the invariant of rule was satisfied for current read under current context.
     * @param pointCloud
     * @param context
     * @return
     */
    public default boolean invariantSatisfied(BodyPointCloud pointCloud, RunningContext context) {
        return this.getInvariant().matched(pointCloud, context) == MatchedStatus.TRUE ;
    }
    public default boolean isPerforming(BodyPointCloud pointCloud, RunningContext context) {
        return this.getDynamic().matched(pointCloud, context) == MatchedStatus.TRUE ;
    }

    /**
     * set and get the score for successfully finishing the actions.
     * @param score
     */
    public void setSuccessScore(double score) ;
    public double successScore() ;
    public default void redo() {

    }
}
